package com.douing.ad.dsp.bidding.rtb;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.alibaba.fastjson.JSON;
import com.douing.ad.dsp.bidding.dto.AdRequestDto;
import com.douing.ad.dsp.bidding.dto.Admt;
import com.douing.ad.dsp.bidding.dto.AppImpressionDto;
import com.douing.ad.dsp.bidding.dto.AppRequestDto;
import com.douing.ad.dsp.bidding.dto.Instl;
import com.douing.ad.dsp.bidding.dto.MatchedCreativeDto;
import com.douing.ad.dsp.bidding.dto.VideoDto;
import com.douing.ad.dsp.bidding.tj.utils.NodeData;
import com.douing.ad.dsp.bidding.utils.RedisUtils;
import com.douing.ad.dsp.business.api.cache.CacheKeyManager;
import com.douing.ad.dsp.business.api.cache.OriginalityDetailInfo;
import com.douing.ad.dsp.bidding.dto.AssetImgDto;
import com.douing.ad.dsp.bidding.dto.ImgType;
import com.douing.ad.dsp.business.api.cache.IconInfo;
import com.douing.ad.dsp.bidding.rtb.MatchCreativeObj;
import com.douing.ad.dsp.bidding.dto.AssetRequestDto;
import com.douing.ad.dsp.bidding.dto.NativeDto;
import com.douing.ad.dsp.bidding.rtb.Common;

public final class CreativeMatch {

	public static List<MatchedCreativeDto> CreativeMatchImp(AdRequestDto request, NodeData nodeData,
			Map<String, NodeData> nodeDataMap) {
		List<MatchedCreativeDto> matchedCreatives = new ArrayList<MatchedCreativeDto>();
		return matchedCreatives;
	}

	private static void getMatchedCreatives(List<MatchedCreativeDto> matchedCreatives,
			Map<String, NodeData> nodeDataMap, MatchCreativeObj matchobj) {
		Date dt = new Date();
		Calendar cal = Calendar.getInstance();
		cal.setTime(dt);
		String week = Common.GetCurrentWeekOfDate(cal);
		String hour = Common.GetCurrentHour(cal);
		long startt = System.currentTimeMillis();
		List<String> matchedCreative = (List<String>) RedisUtils.hvals(matchobj.getKey());
		Common.WriteLog("redis timespan is " + (System.currentTimeMillis() - startt));

		if (matchedCreative != null && !matchedCreative.isEmpty()) {
			for (int j = 0; j < matchedCreative.size(); j++) {
				OriginalityDetailInfo creativeInfo = JSON.parseObject(matchedCreative.get(j),
						OriginalityDetailInfo.class);
				nodeDataMap.put(creativeInfo.getId() + "", new NodeData());
				if (creativeInfo == null || creativeInfo.getDurationInfo() == null) {
					Common.WriteLog("redis data error key is " + matchobj.getKey());
					continue;
				}
				NodeData nodeData = nodeDataMap.get(creativeInfo.getId() + "");
				nodeData.setRequestDate(new Date());
				nodeData.setEntryNum(1);
				// TODO
				nodeData.setCreativeId(creativeInfo.getId() + "");
				// TODO
				nodeData.setStep1(1);
				// video
				boolean isVideo = false;
				boolean isNative = false;
				boolean isBanner = false;
				VideoDto video = matchobj.getImp().getVideo();
				if (video == null && creativeInfo.getAoType() == 4) {
					Common.WriteLog(
							"creative is video and request is banner,creative id is " + creativeInfo.getId() + "!");
					continue;
				}
				if (video != null && creativeInfo.getAoType() == 4) {
					if (video.getMimes() != null && video.getMimes().contains(creativeInfo.getMimes())
							&& video.getMaxduration() >= creativeInfo.getDuration()
							&& video.getMinduration() <= creativeInfo.getDuration()) {
						isVideo = true;
						Common.WriteLog("is video, creative id is " + creativeInfo.getId() + "!");
					} else {
						Common.WriteLog("Filter by video,creative id is " + creativeInfo.getId() + "!");
						continue;
					}
				} else if (matchobj.isNative() && creativeInfo.getAoType() == 3) {
					IconInfo iconInfo = creativeInfo.getIconInfo();
					if ((matchobj.getTitleLen() > 0
							&& creativeInfo.getOriginalityTitle().length() > matchobj.getTitleLen())
							|| (matchobj.getDescLen() > 0
									&& creativeInfo.getOriginalityDesc().length() > matchobj.getDescLen())) {
						Common.WriteLog("native: len of title or desc is not matched!");
						continue;
					} else if (creativeInfo.getUrls() != null && matchobj.getImgLen() > 0
							&& creativeInfo.getUrls().length != matchobj.getImgLen()) {
						Common.WriteLog("native imglen is not matched!");
						continue;
					} else if (iconInfo != null && matchobj.getIconHeight() != 0
							&& (iconInfo.getHeight() != matchobj.getIconHeight()
									|| iconInfo.getWidth() != matchobj.getIconWidth())) {
						Common.WriteLog("native icon is not matched!");
						continue;
					} else {
						isNative = true;
					}
				} else if (!matchobj.isNative() && creativeInfo.getAoType() != 3) {
					isBanner = true;
				} else {
					Common.WriteLog("adtype is not matched!");
				}

				String filterHour = creativeInfo.getDurationInfo().getInterval().get(week);
				if (filterHour != null && !filterHour.equals("all") && !filterHour.contains(hour)) {
					Common.WriteLog("Filter by hour,creative id is " + creativeInfo.getId() + "!");
					continue;
				}
				// TODO
				nodeData.setStep2(1);
				if (!("").equals(matchobj.getUid())) {
					String userKey = CacheKeyManager.getOriginalityFrequentnessKey(Common.GetCurrentDate(dt),
							matchobj.getUid(), String.valueOf(creativeInfo.getId()));
					String userDispCount = RedisUtils.get(userKey);
					if (userDispCount != null
							&& creativeInfo.getEverydayExposureCount() < Long.parseLong(userDispCount)) {
						Common.WriteLog(
								"Filter by Out of EverydayDisplayCount,creative id is " + creativeInfo.getId() + "!");
						continue;
					}
				}
				// TODO
				nodeData.setStep3(1);
				// add plan budget 90% confirm
				String plankey = CacheKeyManager.getPlanFreezePriceKey(String.valueOf(creativeInfo.getPlanId()));
				String planbalancetmp = RedisUtils.get(plankey);
				Long planbalance = 0L;
				if (planbalancetmp != null && !planbalancetmp.isEmpty()) {
					planbalance = Long.valueOf(planbalancetmp);
					if (planbalance < 10000000 && planbalance < creativeInfo.getPlanBudgetPrice() * 0.1) {
						Common.WriteLog("Filter by budget,creative id is " + creativeInfo.getId() + "!");
						continue;
					}
				} else {
					Common.WriteLog("Filter by budget,creative id is " + creativeInfo.getId() + "!");
					continue;
				}
				// TODO
				nodeData.setStep4(1);
				// end add plan budget 90% confirm
				MatchedCreativeDto mc = GetMatchedInfo(creativeInfo, matchobj);
				if (mc.getPlatId() == 1 && mc.getOsType() != -1 && mc.getOsType() != matchobj.getOsType()) {
					Common.WriteLog("Filter by APPOS,creative id is " + creativeInfo.getId() + "!");
					continue;
				}
				matchedCreatives.add(mc);
				Common.WriteLog(
						"key " + matchobj.getKey() + " is matched! matched ad count is " + matchedCreatives.size());
				if (matchedCreatives.size() >= Common.configInfo.getMaxcreatives()) {
					break;
				}
				// TODO
				nodeData.setStep5(1);
			}
		} else {
			Common.WriteLog("bidding match key is " + matchobj.getKey() + " ,memcached no result!");
			return;
		}
	}

	public static MatchedCreativeDto GetMatchedInfo(OriginalityDetailInfo originality, MatchCreativeObj matchobj) {
		MatchedCreativeDto matched = new MatchedCreativeDto();
		matched.setChannelId(originality.getChannelId());
		matched.setId(originality.getId());
		matched.setPlanId(originality.getPlanId());
		matched.setActivityId(originality.getActivityId());
		matched.setWidth(originality.getWidth());
		matched.setHeight(originality.getHeigth());
		matched.setAreaId(matchobj.getAreaId());
		matched.setUrl(originality.getUrl());
		matched.setTargetUrl(originality.getTargetUrl());
		matched.setMaxPrice(originality.getCpmPrice());
		matched.setMatchedcatid(matchobj.getMatchedcatId());
		matched.setCreateUserId(originality.getCreateUserId());
		matched.setCreativeTradeId(originality.getCreativeTradeId());
		matched.setBidfloor(matchobj.getBidfloor());
		matched.setImpid(matchobj.getImpid());
		matched.setCrowds(originality.getCrowds());
		matched.setUid(matchobj.getUid());
		matched.setOsType(originality.getOsType());
		matched.setMediaId(matchobj.getMediaId());
		if (matchobj.isNative()) {
			matched.setTitle(originality.getOriginalityTitle());
			matched.setDesc(originality.getOriginalityDesc());
			matched.setNativeUrls(originality.getUrls());
			matched.setAdmt(Admt.NATIVE);
			if (matchobj.getIconWidth() != 0 && originality.getIconInfo() != null) {
				matched.setIconW(matchobj.getIconWidth());
				matched.setIconH(matchobj.getIconHeight());
				matched.setIconUrl(originality.getIconInfo().getUrl());
			}
		} else if (matchobj.isVideo()) {
			matched.setAdmt(Admt.VIDEO);
			matched.setImageUrl(originality.getImageUrl());
		} else {
			matched.setAdmt(Admt.IMAGE);
		}
		return matched;
	}

	public static Map<String, List<MatchedCreativeDto>> AppCreativeMatchs(AppRequestDto request, NodeData nodeData,
			Map<String, NodeData> nodeDataMap) {
		Map<String, List<MatchedCreativeDto>> retMatcheds = new HashMap<String, List<MatchedCreativeDto>>();
		Long[] categorys = request.getApp().getCat();
		if(categorys==null || categorys.length==0){
			categorys = new Long[]{207l};
		}
		long startt = System.currentTimeMillis();
		long areaId = Common.GetCityId(request.getDevice().getIp());
		Common.WriteLog("ip service time cost:" + (System.currentTimeMillis() - startt) + " ms");
		for (int imp = 0; imp < request.getImp().length; imp++) {
			AppImpressionDto appimp = request.getImp()[imp];
			if (appimp == null) {
				continue;
			}
			if (!retMatcheds.containsKey(appimp.getId())) {
				retMatcheds.put(appimp.getId(), AppMatchImp(request, categorys, areaId, appimp, nodeData, nodeDataMap));
			}
		}
		return retMatcheds;
	}

	private static List<MatchedCreativeDto> AppMatchImp(AppRequestDto request, Long[] categorys, long areaId,
			AppImpressionDto imp, NodeData nodeData, Map<String, NodeData> nodeDataMap) {
		String key = "";
		List<MatchedCreativeDto> matchedCreatives = new ArrayList<MatchedCreativeDto>();
		Long bidfloor = imp.getBidfloor();
		String impid = imp.getId();
		int osType = -1;
		if (request.getDevice().getOs_type() != null) {
			osType = request.getDevice().getOs_type().ordinal();
		}
		String channelid = String.valueOf(request.getChannelId());
		String appId = request.getApp().getId();
		Integer width = 0;
		Integer height = 0;
		Integer titleLen = 0;
		Integer descLen = 0;
		Integer imgLen = 0;
		Integer iconW = 0;
		Integer iconH = 0;
		if (imp.getInstl() == Instl.VIDEO) {
			width = imp.getVideo().getWidth();
			height = imp.getVideo().getHeight();
		} else if (imp.getInstl() == Instl.BANNER) {
			Common.WriteLog("request type is banner!");
			if (imp.getBanner() == null || imp.getBanner().getWidth() == null || imp.getBanner().getHeight() == null) {
				Common.WriteLog("bidding log2 getBanner is " + imp.getBanner());
				Common.WriteLog("bidding log2 getWidth is " + imp.getBanner().getWidth());
				Common.WriteLog("bidding log2 getHeight is " + imp.getBanner().getHeight());
				Common.WriteLog("bidding log2 channelid is " + request.getChannelId());
				return matchedCreatives;
			}
			width = imp.getBanner().getWidth();
			height = imp.getBanner().getHeight();
		} else if (imp.getInstl() == Instl.NATIVE) {
			NativeDto nativedto = imp.getNativedto();
			if (nativedto == null || nativedto.getAssets().length == 0) {
				return matchedCreatives;
			}
			AssetRequestDto[] assets = nativedto.getAssets();
			for (AssetRequestDto asset : assets) {
				if (asset.getImg() != null) {
					AssetImgDto img = asset.getImg();
					if (img.getType() == ImgType.MAIN) {
						width = img.getWidth();
						height = img.getHeight();
						imgLen = img.getImgLen();
					}
					if (img.getType() == ImgType.ICON) {
						iconW = img.getWidth();
						iconH = img.getHeight();
					}
				}
				if (asset.getTitle() != null) {
					titleLen = asset.getTitle().getLen();
				}
				if (asset.getDesc() != null) {
					descLen = asset.getDesc().getLen();
				}
			}
			Common.WriteLog("request type is native!");
		} else {
			Common.WriteLog("request type is unsupport!");
			return matchedCreatives;
		}
		Common.WriteLog("requestid is " + request.getRequestId() + ";bidfloor is " + imp.getBidfloor());

		for (int i = 0; i < categorys.length; i++) {
			long categoryid = categorys[i];
			key = CacheKeyManager.getOriginalityMapKey(channelid, "1", String.valueOf(categoryid),
					String.valueOf(areaId), width.toString(), height.toString());
			Common.WriteLog("begin first matched accurate match , key is " + key);
			MatchCreativeObj matchobj = new MatchCreativeObj();
			matchobj.setKey(key);
			matchobj.setUid("");
			matchobj.setAreaId(areaId);
			matchobj.setMatchedcatId(categoryid);
			matchobj.setBidfloor(bidfloor);
			matchobj.setImpid(impid);
			matchobj.setOsType(osType);
			matchobj.setMediaId(appId);
			matchobj.setMediaDomain(appId);
			matchobj.setImp(imp);
			if (imp.getInstl() == Instl.NATIVE) {
				matchobj.setNative(true);
				matchobj.setTitleLen(titleLen);
				matchobj.setDescLen(descLen);
				matchobj.setImgLen(imgLen);
			} else if (imp.getInstl() == Instl.VIDEO) {
				matchobj.setNative(false);
				matchobj.setVideo(true);
			} else {
				matchobj.setNative(false);
				matchobj.setVideo(false);
			}
			matchobj.setIconWidth(iconW);
			matchobj.setIconHeight(iconH);
			getMatchedCreatives(matchedCreatives, nodeDataMap, matchobj);
			if (Common.OutOfTime(request.getReqStartTime(), nodeData)) {
				for (Map.Entry<String, NodeData> entry : nodeDataMap.entrySet()) {
					entry.getValue().setIsTimeOut(1);
				}
				Common.WriteLog("First matched ,out of time!");
				break;
			}
			if (matchedCreatives.size() >= Common.configInfo.getMaxcreatives()) {
				Common.WriteLog("bidding too many creatives!");
				break;
			}
		}
		if (matchedCreatives.size() == 0) {
			Common.WriteLog("bidding match false!");
		} else {
			Common.WriteLog("bidding match success,number is " + matchedCreatives.size() + "!");
		}
		return matchedCreatives;
	}
}

final class MatchCreativeObj {
	private boolean isVideo = false;
	private String uid;// pc:cookieid
	private String key;// 请求缓存的key
	private Long areaId;// 地域id
	private Long matchedcatId;// 匹配类目id
	private Long bidfloor;// 底价
	private String impid;
	private AppImpressionDto imp;

	private Integer osType;// 操作系统0android，1ios
	private String mediaId;// 媒体id
	private String mediaDomain;// 媒体域名或appid
	private boolean isNative = false;// 是否原生广告
	private Integer titleLen;
	private Integer descLen;
	private Integer imgLen = 1;
	private Integer iconWidth;
	private Integer iconHeight;

	public String getUid() {
		return uid;
	}

	public void setUid(String uid) {
		this.uid = uid;
	}

	public String getKey() {
		return key;
	}

	public void setKey(String key) {
		this.key = key;
	}

	public Long getAreaId() {
		return areaId;
	}

	public void setAreaId(Long areaId) {
		this.areaId = areaId;
	}

	public Long getMatchedcatId() {
		return matchedcatId;
	}

	public void setMatchedcatId(Long matchedcatId) {
		this.matchedcatId = matchedcatId;
	}

	public Long getBidfloor() {
		return bidfloor;
	}

	public void setBidfloor(Long bidfloor) {
		this.bidfloor = bidfloor;
	}

	public String getImpid() {
		return impid;
	}

	public void setImpid(String impid) {
		this.impid = impid;
	}

	public Integer getOsType() {
		return osType;
	}

	public void setOsType(Integer osType) {
		this.osType = osType;
	}

	public String getMediaId() {
		return mediaId;
	}

	public void setMediaId(String mediaId) {
		this.mediaId = mediaId;
	}

	public String getMediaDomain() {
		return mediaDomain;
	}

	public void setMediaDomain(String mediaDomain) {
		this.mediaDomain = mediaDomain;
	}

	public boolean isNative() {
		return isNative;
	}

	public void setNative(boolean isNative) {
		this.isNative = isNative;
	}

	public Integer getTitleLen() {
		return titleLen;
	}

	public void setTitleLen(Integer titleLen) {
		this.titleLen = titleLen;
	}

	public Integer getDescLen() {
		return descLen;
	}

	public void setDescLen(Integer descLen) {
		this.descLen = descLen;
	}

	public Integer getImgLen() {
		return imgLen;
	}

	public void setImgLen(Integer imgLen) {
		this.imgLen = imgLen;
	}

	public boolean isVideo() {
		return isVideo;
	}

	public void setVideo(boolean isVideo) {
		this.isVideo = isVideo;
	}

	public AppImpressionDto getImp() {
		return imp;
	}

	public void setImp(AppImpressionDto imp) {
		this.imp = imp;
	}

	public Integer getIconWidth() {
		return iconWidth;
	}

	public void setIconWidth(Integer iconWidth) {
		this.iconWidth = iconWidth;
	}

	public Integer getIconHeight() {
		return iconHeight;
	}

	public void setIconHeight(Integer iconHeight) {
		this.iconHeight = iconHeight;
	}

}
